package tdd.customer.presentation;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import tdd.customer.domain.customer.Customer;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@SpringBootTest
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
public class CustomerControllerJdbcIT {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Autowired
    private MockMvc mvc;

    @Autowired
    private JdbcTemplate jdbc;

    /*@Autowired
    private CustomerController controller;*/

    @Test
    public void create_should_create_specific_customer() throws Exception {
        jdbc.update("truncate table customer");

        Customer customer = new Customer("张", "三");
        String body = new ObjectMapper().writeValueAsString(customer);

        String id = mvc.perform(MockMvcRequestBuilders
                .post("/api/customers")
                .contentType(MediaType.APPLICATION_JSON)
                .content(body))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString();

        Customer actual = jdbc.queryForObject("select * from customer where id =?",
                BeanPropertyRowMapper.newInstance(Customer.class), Long.valueOf(id));
        Assertions.assertThat(actual).isEqualToIgnoringGivenFields(customer, "id");
    }

    private void prepareDataSet() {
        jdbc.update("truncate table customer");
        jdbc.update("insert into customer(id, first_name, last_name) values(?, ?, ?)", 1L, "张", "三");
        jdbc.update("insert into customer(id, first_name, last_name) values(?, ?, ?)", 2L, "李", "四");
    }

    public String get(String url) throws Exception {
        return mvc.perform(MockMvcRequestBuilders.get(url))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString();
    }

    private static void isEqualTo(String actual, String expected) throws IOException {
        Assertions.assertThat(MAPPER.readTree(actual)).isEqualTo(MAPPER.readTree(expected));
    }

    @Test
    public void findById_should_retrieve_specific_customer_by_id() throws Exception {
        prepareDataSet();
        String actual = get("/api/customers/1");

        Customer expectedCustomer = new Customer("张", "三");
        expectedCustomer.setId(1L);

        ObjectMapper mapper = new ObjectMapper();
        String expected = mapper.writeValueAsString(expectedCustomer);

        isEqualTo(actual, expected);
    }

    @Test
    public void findAll_should_retrieve_all_customer() throws Exception {
        prepareDataSet();
        String actual = get("/api/customers");

        Customer customer1 = new Customer("张", "三");
        Customer customer2 = new Customer("李", "四");
        customer1.setId(1L);
        customer2.setId(2L);
        List<Customer> customers = Arrays.asList(customer1, customer2);

        String expected = MAPPER.writeValueAsString(customers);
        isEqualTo(actual, expected);
    }
}
